import axios from "axios"
import type{AxiosRequestConfig,AxiosResponse,AxiosError} from 'axios'
import {ElMessage as message,ElNotification as notification,ElLoading} from 'element-plus'            
import {getToken} from "@/common/utils"  
import {user as useUser,loading as useLoading} from "@/store"
import router from  "@/router"
     

const baseConfig={
   timeout: 6000,
   baseURL: import.meta.env.VITE_BASE_URL,
   withCredentials: true,
}

export const service=axios.create(baseConfig)    


let elLoading:any

let cancelreq:any           // 用来存储取消本次请求的函数

const noTokenReqUrls=['login','register',]

export interface customReqConfig{
   closeGlobalLoading?:boolean       // 是否关闭全局加载，默认启用 
   loadingTip?:string          // 加载图标下方显示的文字
   closeErrTip?:string           // 请求成功但业务状态码是失败的,此时是否关闭自动的错误提示，默认打开
   urlParams?:string[]             // 动态路由参数，将被拼接到请求的url后面
   GetWholeResponse?:boolean    // 请求成功时，是否返回完整响应数据，默认返回res.data
   [key:string]:any
}
interface myAxiosRequestConfig extends AxiosRequestConfig,customReqConfig{}

const req_interceptors_sunccess:(config:any)=>any= (config:myAxiosRequestConfig) => {
   if(!config.closeGlobalLoading)  elLoading=ElLoading.service({background:'rgba(248, 247, 247,.5)',text:config.loadingTip?config.loadingTip:'加载中...'})
   if(config.urlParams)
   config.url+="/"+config.urlParams.join('/')
   if(config.url && noTokenReqUrls.some(v=>config.url!.includes(v)))
   config.cancelToken = new axios.CancelToken((c) => { cancelreq = c })
   const token = getToken()   
   if (!token)     cancelreq('cancel') 
   else   
      config.headers!.authorization = token
   return config
} 
const req_interceptors_err=(err:AxiosError) => {
   elLoading&&elLoading.close()
   console.log('req interceptors', err)
   return Promise.reject(err)
}
const  res_interceptors_success=(res:AxiosResponse) => {
   const loading=useLoading()
   loading.setLoading(false)
   elLoading&&elLoading.close()
   const config=res.config as myAxiosRequestConfig
   const {msg,code}=res.data
   if(code==undefined || code==200){     // 与后端沟通好，根据后端的业务状态码来写。此处表示只有200才成功
      if(config.GetWholeResponse) return res  
      return res.data        
   }else{
      if(!config.closeErrTip)
      message.error(msg || '未知错误')
      return  {code,msg}
   }
}
const res_interceptors_err= (err:AxiosError<any,any>) => {
   console.log(err)
   const loading=useLoading()
   loading.setLoading(false)
   if (err.response)   // 如果能接收到服务器的响应
   {
      const errMsg = err.response.data.msg || err.message || '未知错误'

      // 根据服务器响应的状态码来统一处理响应。根据接口文档来写
      if (err.response.status === 401)   // 状态码为401说明token无效，此时重定向到登录页
      {
         const user=useUser()

         message.warning('身份过期,请重新登录！')
         user.logout(router.currentRoute.value.fullPath)     // 在pinia中完成了退出登录的逻辑（重置用户信息并且完成页面的跳转）
         return { status: 401, msg: errMsg }
      }
      // 状态码为404或者500说明是后端的问题
      else if (err.response.status === 500 || err.response.status === 404) {
         if (import.meta.env.VITE_NODE_ENV === 'prod')
            message.warning('服务器繁忙,请稍后再试！')
         if (import.meta.env.VITE_NODE_ENV === 'dev')
         notification.error({
            title: '错误',
            dangerouslyUseHTMLString: true,
              message:`
                <p>请求路径:${err.config?.url}</p>
                <p>错误原因:${errMsg}</p>
                `
            // duration:100,
         })

            // console.log('dev err')
         return { status: 500, msg: errMsg }
      }
   }
   else   // 不能接收到服务器的响应，说明网络异常(网不好导致超时或者是断网了)。或者是取消了请求
   {
      //console.log(err)
      if (err.message === 'cancel') {   // 请求被取消
          const user=useUser()
         user.logout(router.currentRoute.value.fullPath)
         message.warning('请先登录！')
         return { status: -2, msg: 'cancel req' }
      }
      message.warning('网络异常,请稍后再试！')
      return { status: -1, msg: 'network err' }
   }
}

service.interceptors.request.use(req_interceptors_sunccess,req_interceptors_err)
service.interceptors.response.use(res_interceptors_success,res_interceptors_err)


/**
 * @description get请求
 * @param reqUrl 
 * @param query 
 * @param config 
 * @returns 
 */
export function getReq(reqUrl:string, query = {},config?:customReqConfig) {
   return service({
      url: reqUrl,
      params: query,
      ...config,
   })
}

/**
 * @description post请求
 * @param reqUrl 
 * @param body 
 * @param config 
 * @returns 
 */
export function postReq(reqUrl:string, body = {},config?:customReqConfig) {
   return service({
      method: "post",
      url: reqUrl,
      data: body,
      ...config,  // 这里的config会被合并到请求拦截的config、err.config 和 响应拦截的res.config、err.config
   })
}

/**
 * @description 文件上传请求
 * @param reqUrl 
 * @param formData 
 * @param config 
 * @returns 
 */
export function uploadFileReq(reqUrl:string, formData = {},config?:customReqConfig) {
   return service({
      url: reqUrl,
      method: 'post',
      headers: { 'Content-Type': 'multipart/form-data', },
      data: formData,
      ...config,
   })
}

/**
 * @description 获取blob的请求。当接口响应文件流时，请通过该请求函数配合 utils.downloadFileByBlob完成下载，utils.printFileByBlob完成打印
 * @param reqUrl 
 * @param body 
 * @param config 
 * @returns 
 */
export function getBlobByFileStreamReq(reqUrl:string, body = {},config?:customReqConfig){
   return service({
      method: "post",
      url: reqUrl,
      data: body,
      responseType: 'blob',
      ...{GetWholeResponse:true,...config},
   })
}